package com.shermanzhou.nio;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.SortedMap;

/**
 * 一. 通道Channel的主要实现类
 *      FileChannel
 *      SocketChannel
 *      ServerSocketChannel
 *      DatagramChannel
 *
 * 二. 获取通道
 *  1. java为支持通道的类提供了 getChannel() 获取通道
 *      本地IO
 *         FileInputStream/FileOutputStream
 *         RandomAccessFile
 *
 *      网络IO
 *         Socket
 *         ServerSocket
 *         DatagramSocket
 *  2. 在 JDK1.7 中的 NIO2 针对各个通道提供了静态方法 open()
 *  3. 在 JDK1.7 中的 NIO2 提供的 Files 工具类的 newByteChannel()
 *
 * 三. 通道之间的数据传输
 *  1. transferFrom()
 *  2. transferTo()
 *
 * @author zhouchaoqun
 * @date 2018/10/24 上午10:35
 */
public class ChannelTest {

    private long start = 0;

    @Before
    public void init() {
        start = System.currentTimeMillis();
    }

    @After
    public void after() {
        System.out.println("execute time: " + (System.currentTimeMillis() - start));
    }

    /**
     * 利用通道完成文件的复制（非直接缓冲区）
     */
    @Test
    public void test1() {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            fis = new FileInputStream("/Users/zhouchaoqun/Downloads/BaiduYun/尚硅谷/Mybatis/视频1/4.尚硅谷_MyBatis_接口式编程.avi");
            fos = new FileOutputStream("/Users/zhouchaoqun/Downloads/BaiduYun/尚硅谷/Mybatis/2.avi");

            inChannel = fis.getChannel();
            outChannel = fos.getChannel();

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while(inChannel.read(buffer) != -1) {
                buffer.flip();
                outChannel.write(buffer);
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 利用通道复制文件 （直接缓冲区）
     */
    @Test
    public void test2() {
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            inChannel = FileChannel.open(Paths.get("/Users/zhouchaoqun/Downloads/BaiduYun/尚硅谷/Mybatis/视频1/4.尚硅谷_MyBatis_接口式编程.avi"), StandardOpenOption.READ);
            outChannel = FileChannel.open(Paths.get("/Users/zhouchaoqun/Downloads/BaiduYun/尚硅谷/Mybatis/3.avi"), StandardOpenOption.WRITE, StandardOpenOption.READ,StandardOpenOption.CREATE);

            MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
            MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

            byte[] dest = new byte[inMappedBuf.limit()];
            inMappedBuf.get(dest);
            outMappedBuf.put(dest);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 通道之间的数据传输
     */
    @Test
    public void test3() throws IOException {
        FileChannel inChannel = FileChannel.open(Paths.get("/Users/zhouchaoqun/Downloads/BaiduYun/尚硅谷/Mybatis/视频1/4.尚硅谷_MyBatis_接口式编程.avi"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("/Users/zhouchaoqun/Downloads/BaiduYun/尚硅谷/Mybatis/4.avi"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);

//        inChannel.transferTo(0, inChannel.size(), outChannel);
        outChannel.transferFrom(inChannel, 0, inChannel.size());

        outChannel.close();
        inChannel.close();
    }

    /**
     * 分散与聚集
     */
    @Test
    public void test4() throws IOException {
        RandomAccessFile file1 = new RandomAccessFile("1.png", "rw");

        FileChannel inChannel = file1.getChannel();

        ByteBuffer buf1 = ByteBuffer.allocate(100);
        ByteBuffer buf2 = ByteBuffer.allocate(1024);
        ByteBuffer[] bufs = new ByteBuffer[]{buf1, buf2};

        RandomAccessFile file2 = new RandomAccessFile("2.png", "rw");

        FileChannel outChannel = file2.getChannel();

        while (inChannel.read(bufs) != -1) {
            System.out.println(buf1.position());
            System.out.println(buf2.position());

            for (ByteBuffer buf : bufs) {
                buf.flip();
            }

            outChannel.write(bufs);

            for (ByteBuffer buf : bufs) {
                buf.clear();
            }
        }

        outChannel.close();
        inChannel.close();
        file2.close();
        file1.close();
    }

    /**
     * 编解码
     * Charset 字符集
     */
    @Test
    public void test5() {
        SortedMap<String, Charset> charsets = Charset.availableCharsets();
        for(Map.Entry<String, Charset> charsetEntry : charsets.entrySet()) {
            System.out.println(charsetEntry);
        }
    }

    @Test
    public void test6() {
        CharBuffer cBuf = CharBuffer.allocate(1024);
        cBuf.put("你好吗？");
        cBuf.flip();

        Charset utf8charset = Charset.forName("UTF-8");
        ByteBuffer bBuf = utf8charset.encode(cBuf);

        for (int i = 0; i < bBuf.limit(); i++) {
            System.out.println(bBuf.get());
        }
        bBuf.rewind();

        CharBuffer cBuf2 = utf8charset.decode(bBuf);
        System.out.println(cBuf2.toString());

    }
}
